#pragma once

#include <spdlog/spdlog.h>
#include <chrono>
#include <ratio>
#include "utils.hpp"

#include "BS_thread_pool.hpp"

namespace qbe::ecs {

class ThreadPool {
 public:
  static ThreadPool* getInstance();
  std::shared_ptr<BS::thread_pool<>> pool() { return m_pool; };

 private:
  ThreadPool() {
    unsigned int num_threads = std::thread::hardware_concurrency();
    m_pool = std::make_shared<BS::thread_pool<>>(num_threads * 1.2);
    // size_t thread_count = m_pool->get_thread_count();
    // m_pool->reset(thread_count * 1.5);
  };
  static ThreadPool* instance;
  std::shared_ptr<BS::thread_pool<>> m_pool;
};

template <typename T>
class FunctionTimer {
 public:
  using Clock = std::chrono::high_resolution_clock;
  using ClassType = T;

  // 测量无参、无返回值的成员函数
  template <typename Func>
  static void measure(ClassType* obj, Func ClassType::* func, std::string_view func_name) {
    auto start = Clock::now();

    (obj->*func)();  // 调用成员函数

    auto end = Clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();

    SPDLOG_INFO("Function [{}] executed in {} ms", func_name, duration);
  }

  // 支持带参数的成员函数（可扩展）
  template <typename Func, typename... Args>
  static auto measure_with_args(ClassType* obj, Func ClassType::* func, std::string_view func_name, Args&&... args)
      -> decltype((obj->*func)(std::forward<Args>(args)...)) {
    auto start = Clock::now();

    auto result = (obj->*func)(std::forward<Args>(args)...);

    auto end = Clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();

    SPDLOG_INFO("Function [{}] executed in {} ms", func_name, duration);

    return result;
  }
};

// 使用宏简化调用
#define MEASURE_FUNC(obj, func) FunctionTimer<std::remove_reference_t<decltype(*(obj))>>::measure(obj, func, #func)

#define MEASURE_FUNC_WITH_ARGS(obj, func, ...) \
  FunctionTimer<std::remove_reference_t<decltype(*(obj))>>::measure_with_args(obj, func, #func, __VA_ARGS__)

class Time {
 private:
  std::chrono::time_point<std::chrono::high_resolution_clock> _first_update;
  std::chrono::time_point<std::chrono::high_resolution_clock> _last_update;
  std::chrono::duration<double, std::ratio<1>> _last_update_delta;

  std::chrono::high_resolution_clock::time_point start_time;
  bool is_running = false;

 public:
  Time() {};
  ~Time() {};

  std::chrono::duration<double, std::ratio<1>> startup();

  void update_with_instant(std::chrono::time_point<std::chrono::high_resolution_clock>&& instant);

  std::chrono::duration<double, std::ratio<1>> delta();

  double delta_seconds();

  void Start();
  double TotalTime() const;
  double End();
};

}  // namespace qbe::ecs
